
import {
    BASE_BLOCK,
    FUNC_BLOCK,
    TASK_BLOCK,
    LOGS_BLOCK,
}   from "./block-type.js"


import  P2P from "../p2p/p2p.js"
import Chr from "../qbasics/pack/Chr.js"
import Wan from "../qbasics/utils/Wan";
import Round from "../qbasics/basics/Round";
const CryptoJS = require('crypto-js')
const   crypto = require('crypto');
const fs = require('fs');
/**
 * 平年 525600分钟
 * 闰年 527040分钟
 * @returns {Block}
 */

export default  class CoreModule{



    constructor(){
        this.paraBlock=[new Chr()]
        this.baseBlock=[new Chr(),new Chr,new Chr()]
        this.funcBlock=[];
        this.taskBlock=[];
        this.logsBlock=[];
        this.difficulty = 4
        this.src="";
        this.p2p=new P2P(this);
    }





    /**
     * 保存模块
     */

      saveModule(id,data) {
        coreModeule.saveModule(round);
    }

    /**
     * 创建模块
     */
      createModule(nid,id,data) {
        coreModeule.createModule(round);
    }
    /**
     *设置目录
     */

    confSrc(src){
        this.src=src;
    }


    /**
     * 监听端口
     */
    startServer(port){
        this.p2p.startServer(port);
    }

    /**
     * 创建一个连接
     * @param host
     * @param port
     */
    connectToPeer(host, port){
        this.p2p.  connectToPeer(host, port);
    }
    /**
     *  加载 数据
     * @param data
     */
    loadData(data){
        //读取本地配置 用户等等
        let buff= new Uint8Array(data);
        let chr= new Chr().loadData(buff);
        this.paraBlock[0]=chr;
    }

    /**
     *
     * @returns {uint8array[]|*[]}
     */
    loadBaseBlock(){
        //读取基础模块
        let data=fs.readFileSync( this.src+"/1");
        let buff= new Uint8Array(data);
        let listWan= Wan.buffToWans(buff);
        let chr= new Chr().loadData(data);
        this.baseBlock[0]=chr;
    }

    outData(){
      return  this.paraBlock[0].outData()
    }

    /**
     * 根据特定id读取文件
     * @returns {Array|*}
     */
    loadDataById(id){
        //读取基础模块
        let data=fs.readFileSync( this.src+"/"+id);
        let buff= new Uint8Array(data);
        let listWan= Wan.buffToWans(buff);
        return new Chr().loadData(data);

    }

    delChrById(id){
        //读取基础模块
        fs.unlink ( this.src+"/"+id);
    }

    writeChrById(id,chr){
        //读取基础模块
        fs.writeFileSync ( this.src+"/"+id,chr.outData());
    }





    get () {
        return this.logsBlock
    }

    get latestBlock () {
        return this.logsBlock[this.logsBlock.length - 1]
    }

    mine (seed) {
        const newBlock = this.generateNextBlock(seed)
        if(this.addBlock(newBlock)) {
            console.log("🎉  祝贺 你！一个新的区块被开采了. 💎")
        }
    }

    replaceChain (newBlocks) {
        if (!this.isValidChain(newBlocks)) {
            console.log("❌ 更换链条无效。不会替换现有区块链.")
            return null;
        }

        if (newBlocks.length <= this.logsBlock.length) {
            console.log("❌  更换的链条比原来的短。不会取代现有的区块链。")
            return null;
        }

        console.log('✅  收到的区块链有效。用接收到的区块链替换当前区块链')
        this.logsBlock = newBlocks.map(json => new Block(
            json.index, json.previousHash, json.timestamp, json.data, json.hash, json.nonce
        ))
    }

    isValidChain (blockchainToValidate) {
        if (JSON.stringify(blockchainToValidate[0]) !== JSON.stringify(Block.genesis)) {
            return false
        }

        const tempBlocks = [blockchainToValidate[0]]
        for (let i = 1; i < blockchainToValidate.length; i = i + 1) {
            if (this.isValidNewBlock(blockchainToValidate[i], tempBlocks[i - 1])) {
                tempBlocks.push(blockchainToValidate[i])
            } else {
                return false
            }
        }
        return true
    }

    addBlock (newBlock) {
        if (this.isValidNewBlock(newBlock, this.latestBlock)) {
            this.logsBlock.push(newBlock);
            return true;
        }
        return false;
    }

    addBlockFromPeer(json) {
        if (this.isValidNewBlock(json, this.latestBlock)) {
            this.logsBlock.push(new Block(
                json.index, json.previousHash, json.timestamp, json.data, json.hash, json.nonce
            ))
        }
    }

    calculateHashForBlock (block) {
        return this.calculateHash(block.index, block.previousHash, block.timestamp, block.data, block.nonce)
    }

    calculateHash (index, previousHash, timestamp, data, nonce) {
        return CryptoJS.SHA256(index + previousHash + timestamp + data + nonce).toString()
    }

    isValidNewBlock (newBlock, previousBlock) {
        const blockHash = this.calculateHashForBlock(newBlock);

        if (previousBlock.index + 1 !== newBlock.index) {
            console.log('❌  新块的索引无效')
            return false
        } else if (previousBlock.hash !== newBlock.previousHash) {
            console.log('❌  新块的上一个哈希值无效')
            return false
        } else if (blockHash !== newBlock.hash) {
            console.log(`❌  哈希无效: ${blockHash} ${newBlock.hash}`)
            return false
        } else if (!this.isValidHashDifficulty(this.calculateHashForBlock(newBlock))) {
            console.log(`❌  无效哈希不满足难度要求: ${this.calculateHashForBlock(newBlock)}`);
            return false;
        }
        return true
    }

    generateNextBlock (blockData) {
        const previousBlock = this.latestBlock;
        const nextIndex = previousBlock.index + 1;
        const nextTimestamp = new Date().getTime() / 1000
        let nonce = 0;
        let nextHash = '';
        while(!this.isValidHashDifficulty(nextHash)) {
            nonce = nonce + 1;
            nextHash = this.calculateHash(nextIndex, previousBlock.hash, nextTimestamp, blockData, nonce);
        }
        const nextBlock = new Block(nextIndex, previousBlock.hash, nextTimestamp, blockData, nextHash, nonce);
        return nextBlock;
    }

    isValidHashDifficulty(hash) {
        for (var i = 0, b = hash.length; i < b; i ++) {
            if (hash[i] !== '0') {
                break;
            }
        }
        return i === this.difficulty;
    }


    /**
     * 判断类型
     */

    isBaseBlock(){}
    isFunc_Block(){}
    isTaskBlock(){}
    isLogsBlock(){}


    /**
     * 相互校验
     * mutualCheck
     */
    mutualValid(id){

         switch (id){

             case 1:
                 var  signture2= this.baseBlock[id].findSignture(2);  //获取签名
                 var  signture3= this.baseBlock[id].findSignture(3);  //获取签名
                 var verify = crypto.createVerify('RSA-SHA256');
                 var data=this.baseBlock[id].findData();
                 var publicKey2=this.baseBlock[2].findPublicKey();
                 var publicKey2=this.baseBlock[3].findPublicKey();
                 verify.update(data);
                 var result2 = verify.verify( publicKey2 , signture2, 'hex');	//验证签名
                 var result3 = verify.verify( publicKey3 , signture3, 'hex');	//验证签名
                 if( result2&&result3) return true
                 break
             case 2:
                 var  signture1= this.baseBlock[id].findSignture(1);  //获取签名
                 var  signture3= this.baseBlock[id].findSignture(3);  //获取签名
                 var verify = crypto.createVerify('RSA-SHA256');
                 var data=this.baseBlock[id].findData();
                 var publicKey2=this.baseBlock[1].findPublicKey();
                 var publicKey2=this.baseBlock[3].findPublicKey();
                 verify.update(data);
                 var result1 = verify.verify( publicKey2 , signture1, 'hex');	//验证签名
                 var result3 = verify.verify( publicKey3 , signture3, 'hex');	//验证签名
                 if( result1&&result3) return true
                 break
             default:

                 var  signture1= this.baseBlock[id].findSignture(1);  //获取签名
                 var  signture2= this.baseBlock[id].findSignture(2);  //获取签名
                 var verify = crypto.createVerify('RSA-SHA256');
                 var data=this.baseBlock[id].findData();
                 var publicKey2=this.baseBlock[1].findPublicKey();
                 var publicKey2=this.baseBlock[2].findPublicKey();
                 verify.update(data);
                 var result1 = verify.verify( publicKey2 , signture1, 'hex');	//验证签名
                 var result2 = verify.verify( publicKey2 , signture2, 'hex');	//验证签名
                 if( result1&&result2) return true
                 break

         }
        return false
    }



    /**
     *
     * 升级基础模块之后，校验第一个模块
     * 主要初始化第一个模块
     * 第一个块的交易
     * 功能模块从4开始
     * 任务模块从10000开始
     * 记录模块从100000000开始
     *
     */
    firstValid(id){
        switch (id){

            case 4:
                var  signture3= this.baseBlock[id].findSignture(3);  //获取签名
                var verify = crypto.createVerify('RSA-SHA256');
                var data=this.baseBlock[id].findData();
                var publicKey3=this.baseBlock[3].findPublicKey();
                verify.update(data);
                var result3 = verify.verify( publicKey3 , signture3, 'hex');	//验证签名
                return result3
                break
            case 10000:
                var  signture2= this.baseBlock[id].findSignture(2);  //获取签名
                var verify = crypto.createVerify('RSA-SHA256');
                var data=this.baseBlock[id].findData();
                var publicKey2=this.baseBlock[2].findPublicKey();
                verify.update(data);
                var result2 = verify.verify( publicKey2 , signture2, 'hex');	//验证签名
                return result2
                break
            case 100000000:
                var  signture1= this.baseBlock[id].findSignture(1);  //获取签名
                var verify = crypto.createVerify('RSA-SHA156');
                var data=this.baseBlock[id].findData();
                var publicKey1=this.baseBlock[1].findPublicKey();
                verify.update(data);
                var result1 = verify.verify( publicKey1 , signture1, 'hex');	//验证签名
                return result1
                break

        }
        return false
    }

    /**
     * 区块链校验
     * 确定起始模块，然后开始和区块链判断一样
     */
    chainValid(newBlock, previousBlock) {
        const blockHash = this.calculateHashForBlock(newBlock);

        if (previousBlock.index + 1 !== newBlock.index) {
            console.log('❌  新块的索引无效')
            return false
        } else if (previousBlock.hash !== newBlock.previousHash) {
            console.log('❌  新块的上一个哈希值无效')
            return false
        } else if (blockHash !== newBlock.hash) {
            console.log(`❌  哈希无效: ${blockHash} ${newBlock.hash}`)
            return false
        } else if (!this.isValidHashDifficulty(this.calculateHashForBlock(newBlock))) {
            console.log(`❌  无效哈希不满足难度要求: ${this.calculateHashForBlock(newBlock)}`);
            return false;
        }
        return true
    }


    /**
     * 功能校验
     * 待定
     *
     */
    funcValid(id){
        if (previousBlock.index + 1 !== newBlock.index) {
            console.log('❌  新块的索引无效')
            return false
        } else if (previousBlock.hash !== newBlock.previousHash) {
            console.log('❌  新块的上一个哈希值无效')
            return false
        } else if (blockHash !== newBlock.hash) {
            console.log(`❌  哈希无效: ${blockHash} ${newBlock.hash}`)
            return false
        }
        var  signture3= this.baseBlock[id].findSignture(3);  //获取签名
        var verify = crypto.createVerify('RSA-SHA256');
        var data=this.baseBlock[id].findData();
        var publicKey3=this.baseBlock[3].findPublicKey();
        verify.update(data);
        var result3 = verify.verify( publicKey3 , signture3, 'hex');	//验证签名
        return result3
    }
}


